6250. Варка овощей
Хитрость
варки овощей состоит в том, чтобы все кусочки были примерно одинакового
размера. Если они не являются таковыми, то маленькие кусочки получаются слишком
мягкими, а крупные недоваренными. К счастью, Вы слышали о кухонном ноже, хотя
предупреждения Ваших родителей об использовании острых инструментов до сих пор
находятся в Вашей голове. Поэтому Вы хотите использовать его как можно меньше.
Вы можете взять кусок овоща весом w и
разрезать его произвольным образом на две части с весами wleft и wright,
где wleft + wright = w. Эту операцию назовем "разрез".
Зная
размеры имеющихся кусков овощей, определить наименьшее количество разрезов,
после выполнения которых соотношение между наименьшим и наибольшим куском будет
больше заданного порогового значения.
Вход. Начинается
с действительного числа t (0.5 < t < 1) с 2 десятичными цифрами и
натурального числа n (n ≤ 1000). Далее идут n целых положительных весов w1, w2, ..., wn.
Все веса меньше чем 106.
Выход. Вывести
минимальное количество разрезов, после выполнения которых соотношение между
наименьшим и наибольшим куском будет больше t.
Считайте, что число необходимых разрезов меньше 500. Чтобы избежать проблем с
действительными числами, предположим, что оптимальный ответ для отношения t будет таким же, как и для отношения t + 0.0001.
Пример входа 1 |
Пример выхода 1 |
0.99 3 2000 3000 4000 |
6 |
|
|
Пример входа 2 |
Пример выхода 2 |
0.80 2 1000 1400 |
3 |
структуры данных - очередь с
приоритетами
Куски
всегда следует разрезать на равное количество частей. Изначально считаем, что
каждый из них разрезан на 1 кусок. Для каждого куска будем хранить его вес weight и количество частей parts, на которое он на данный момент разрезан
(то есть кусок храним в виде пары (weight,
parts)). Например, во втором тесте
следует разрезать первый кусок на две части, а второй на три:
Куски
храним в max – куче, где они сортируются по убыванию веса их одной части (то
есть значению weight / parts). Для приведенного примера куча
содержит две пары: ((1000, 2), (1400, 3)), причем именно в таком порядке, так
как размер одной части первого овоща составляет 500, а второго – 466.7.
Вычислим
величину минимального куска minWeight.
Пока его отношение к величине максимального куска (хранящегося на вершине кучи)
будет меньше t, выполняем следующие
действия: извлечем из кучи овощ, вес одного куска которого наибольший. Если
овощ на данный момент разрезан на parts
частей, то увеличим в нем число разрезов на 1 и снова занесем в кучу. После
каждого разрезания пересчитаем значение minWeight.
Реализация алгоритма
Информацию
о разрезах овощей храним в структуре vegetable: исходный кусок массой weight разделен на parts частей, причем вес одной части составляет weight / parts. По этому весу одной части и будем сортировать куски,
реализуем соответствующий компаратор.
struct vegetable
{
double weight;
int parts;
vegetable(double weight, int
parts) :
weight(weight), parts(parts) {};
int operator< (const vegetable &a) const
{
return weight / parts < a.weight / a.parts;
}
};
Сохраним куски в очереди с приоритетами heap.
priority_queue<vegetable> heap;
Основная часть программы. Читаем входные данные. Ищем
вес минимального куска minWeight.
Информацию о кусках заносим в очередь: изначально все они разделены на 1 часть.
scanf("%lf %d",&t,&n);
minWeight = 1e10;
for(i = 0; i < n; i++)
{
scanf("%lf",&w);
heap.push(vegetable(w,1));
if (w < minWeight) minWeight = w;
}
Количество разрезов подсчитываем в переменной cuts.
cuts = 0;
for(;;)
{
Берем овощ с максимальным весом одной части cur.weight / cur.parts.
vegetable cur =
heap.top();
Если отношение весов минимальной minWeight и максимальной части не меньше t, то останавливаем процесс деления.
if (minWeight / (cur.weight / cur.parts) >= t) break;
heap.pop(); cuts++;
Увеличиваем количество разрезов в овоще cur.
cur.parts++;
Пересчитываем вес минимальной части.
minWeight =
min(minWeight,cur.weight / cur.parts);
Заносим обновленный кусок в очередь.
heap.push(cur);
}
Выводим ответ.
printf("%d\n",cuts);